home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / dfpp01.zip / POPDOWN.CPP < prev    next >
C/C++ Source or Header  |  1992-11-21  |  8KB  |  382 lines

  1. // ------------- popdown.cpp
  2.  
  3. #include <ctype.h>
  4. #include "desktop.h"
  5. #include "popdown.h"
  6. #include "menusel.h"
  7.  
  8. void PopDown::OpenWindow()
  9. {
  10.     windowtype = PopdownWindow;
  11.     if (windowstate == CLOSED)
  12.         ListBox::OpenWindow();
  13.     SetAttribute(BORDER | SHADOW | SAVESELF | NOCLIP);
  14.     selection = 0;
  15.     DblBorder = False;
  16.     isopen = False;
  17.     SetColors();
  18.     iscascaded = False;
  19.     if (selections != NULL)    {
  20.         MenuDimensions();
  21.         SetTextLength(menuwidth * menuheight);
  22.         for (int i = 0; i < menuheight; i++)    {
  23.             MenuSelection &ms = **(selections+i);
  24.             BuildMenuLine(i);
  25.             if (ms.type == CASCADER)    {
  26.                 ms.cascade = new PopDown(this, ms.cascaders);
  27.                 ms.cascade->isCascaded() = True;
  28.             }
  29.         }
  30.         rect.Right() = rect.Left() + menuwidth;
  31.         rect.Bottom() = rect.Top() + menuheight + 1;
  32.     }
  33. }
  34.  
  35. void PopDown::CloseWindow()
  36. {
  37.     if (selections != NULL)    {
  38.         // --- delete all cascader popdowns
  39.         for (int i = 0; ; i++)    {
  40.             MenuSelection &ms = **(selections+i);
  41.             if (ms.type == TERMINATOR)
  42.                 break;
  43.             if (ms.type == CASCADER && ms.cascade != NULL)
  44.                 delete ms.cascade;
  45.         }
  46.     }
  47.     ListBox::CloseWindow();
  48. }
  49.  
  50. void PopDown::OpenMenu(int left, int top)
  51. {
  52.     Rect rc(0, 0, desktop.screen().Width()-1, desktop.screen().Height()-1);
  53.     DFWindow *Wnd = parent;
  54.     while (Wnd != NULL && Wnd->WindowType() == PopdownWindow)
  55.         Wnd = Wnd->Parent();
  56.     if (Wnd != NULL && (Wnd = Wnd->Parent()) != NULL)    {
  57.         Rect rc = Wnd->ClientRect();
  58.         left = min(max(left, rc.Left()), rc.Right() - ClientWidth());
  59.         top = min(max(top, rc.Top()), rc.Bottom() - ClientHeight());
  60.     }
  61.     left = min(max(left, rc.Left()), rc.Right()-ClientWidth()-1);
  62.     top = min(max(top, rc.Top()), rc.Bottom()-ClientHeight()-1);
  63.     isopen = True;
  64.     Move(left, top);
  65.     CaptureFocus();
  66.     Paint();        // in case a command attribute changed
  67. }
  68.  
  69. void PopDown::CloseMenu(Bool SendESC)
  70. {
  71.     if (isopen)    {
  72.         // ------- close any open cascaded menus
  73.         PopDown *Wnd = (PopDown *)first;
  74.         while (Wnd != NULL)    {
  75.             Wnd->CloseMenu(False);
  76.             Wnd = (PopDown *) (Wnd->next);
  77.         }
  78.         Hide();
  79.         isopen = False;
  80.         ReleaseFocus();
  81.         if (parent && !iscascaded && SendESC)
  82.             parent->Keyboard(ESC);
  83.     }
  84. }
  85.  
  86. void PopDown::Show()
  87. {
  88.     if (isopen)
  89.         ListBox::Show();
  90. }
  91.  
  92. // -------- build a menu line
  93. void PopDown::BuildMenuLine(int sel)
  94. {
  95.     int wd = menuwidth;
  96.     String ln;
  97.     if (selections[sel]->type == SEPARATOR)
  98.         ln = String(--wd, LINE);
  99.     else    {
  100.         ln = String(" ");
  101.         ln += *(selections[sel]->label);
  102.         int r = wd-ln.Strlen();
  103.         ln += String(r, ' ');
  104.         if (selections[sel]->type == CASCADER)
  105.             ln[wd-1] = CASCADEPOINTER;
  106.     }
  107.     AddText(ln);
  108. }
  109.  
  110. // -------- compute menu width
  111. void PopDown::MenuDimensions()
  112. {
  113.     int txlen = 0;
  114.     for (int i = 0; selections[i]->type != TERMINATOR; i++)    {
  115.         if (selections[i]->type != SEPARATOR)    {
  116.             int lblen = (selections[i]->label)->Strlen()-1;
  117.             txlen = max(txlen, lblen);
  118.         }
  119.     }
  120.     menuwidth = txlen+4;
  121.     menuheight = i;
  122. }
  123.  
  124. // -------- set the fg/bg colors for the window 
  125. void PopDown::SetColors()
  126. {
  127.     colors.fg = BLACK;
  128.     colors.bg = CYAN;
  129.     colors.sfg = BLACK;
  130.     colors.sbg = LIGHTGRAY;
  131.     colors.ffg = BLACK;
  132.     colors.fbg = CYAN;
  133.     colors.hfg = DARKGRAY;    // Inactive FG
  134.     colors.hbg = CYAN;        // Inactive FG
  135.     shortcutfg = RED;
  136. }
  137.  
  138. void PopDown::DisplayMenuLine(int lno)
  139. {
  140.     if (isopen)    {
  141.         int fg, bg;
  142.         int isActive = selections[lno]->isEnabled();
  143.         int sfg = shortcutfg;
  144.         if (lno == selection)    {
  145.             fg = colors.sfg;
  146.             bg = colors.sbg;
  147.         }
  148.         else if (isActive)    {
  149.             fg = colors.fg;
  150.             bg = colors.bg;
  151.         }
  152.         else     {
  153.             fg = colors.hfg;
  154.             bg = colors.hbg;
  155.         }
  156.         if (!isActive)
  157.             shortcutfg = fg;
  158.         WriteShortcutLine(lno, fg, bg);
  159.         shortcutfg = sfg;
  160.     }
  161. }
  162.  
  163. void PopDown::ClearSelection()
  164. {
  165.     if (selection != -1)    {
  166.         int sel = selection;
  167.         selection = -1;
  168.         DisplayMenuLine(sel);
  169.     }
  170. }
  171.  
  172. void PopDown::SetSelection(int sel)
  173. {
  174.     ClearSelection();
  175.     if (sel >= 0 && sel < wlines)    {
  176.         selection = sel;
  177.         DisplayMenuLine(sel);
  178.     }
  179. }
  180.  
  181. void PopDown::Paint()
  182. {
  183.     if (text == NULL)
  184.         ListBox::Paint();
  185.     else    {
  186.         for (int i = 0; i < wlines; i++)    {
  187.             if (selections[i]->type == TOGGLE)    {
  188.                 char *cp = TextLine(i);
  189.                 if (selections[i]->toggle == On)
  190.                     *cp = CheckMark();
  191.                 else
  192.                     *cp = ' ';
  193.             }
  194.             DisplayMenuLine(i);
  195.         }
  196.     }
  197. }
  198.  
  199. void PopDown::Border()
  200. {
  201.     if (isopen && isVisible())    {
  202.         int fg = colors.ffg;
  203.         int bg = colors.fbg;
  204.         int rt = Width()-1;
  205.         ListBox::Border();
  206.         for (int i = 0; i < wlines; i++)    {
  207.             if (selections[i]->type == SEPARATOR)    {
  208.                 WriteWindowChar(LEDGE, 0, i+1, fg, bg);
  209.                 WriteWindowChar(REDGE, rt, i+1, fg, bg);
  210.             }
  211.         }
  212.     }
  213. }
  214.  
  215. Bool PopDown::AcceleratorKey(int key)
  216. {
  217.     for (int i = 0; i < wlines; i++)    {
  218.         MenuSelection &ms = **(selections+i);
  219.         if (key == ms.accelerator)    {
  220.             SetSelection(i);
  221.             Choose();
  222.             return True;
  223.         }
  224.     }
  225.     return False;
  226. }
  227.  
  228. Bool PopDown::ShortCutKey(int key)
  229. {
  230.     key = tolower(key);
  231.     for (int i = 0; i < wlines; i++)    {
  232.         MenuSelection &ms = **(selections+i);
  233.         int off = ms.label->FindChar(SHORTCUTCHAR);
  234.         if (off != -1)    {
  235.             String &cp = *ms.label;
  236.             int c = cp[off+1];
  237.             if (key == tolower(c))    {
  238.                 SetSelection(i);
  239.                 Choose();
  240.                 return True;
  241.             }
  242.         }
  243.     }
  244.     return False;
  245. }
  246.  
  247. void PopDown::Keyboard(int key)
  248. {
  249.     if (AcceleratorKey(key))
  250.         return;
  251.     if (ShortCutKey(key))
  252.         return;
  253.     switch (key)    {
  254.         case UP:
  255.             if (selection == 0)    {
  256.                 SetSelection(wlines-1);
  257.                 return;
  258.             }
  259.             if (selections[selection-1]->type == SEPARATOR)    {
  260.                 SetSelection(selection-2);
  261.                 return;
  262.             }
  263.             break;
  264.         case DN:
  265.             if (selection == wlines-1)    {
  266.                 SetSelection(0);
  267.                 return;
  268.             }
  269.             if (selections[selection+1]->type == SEPARATOR)    {
  270.                 SetSelection(selection+2);
  271.                 return;
  272.             }
  273.             break;
  274.         case ESC:
  275.             CloseMenu(ParentisMenu());
  276.             return;
  277.         case FWD:
  278.         case BS:
  279.             CloseMenu(False);
  280.             if (parent != NULL)    {
  281.                 parent->Keyboard(key);
  282.                 return;
  283.             }
  284.             break;
  285.         default:
  286.             break;
  287.     }
  288.     ListBox::Keyboard(key);
  289. }
  290.  
  291. void PopDown::ShiftChanged(int sk)
  292. {
  293.        if (sk & ALTKEY)
  294.         CloseMenu(ParentisMenu());
  295. }
  296.  
  297. // ---------- Left mouse button was clicked
  298. void PopDown::LeftButton(int mx, int my)
  299. {
  300.     if (ClientRect().Inside(mx, my))    {
  301.         if (my != prevmouseline)    {
  302.             int y = my - ClientTop();
  303.             if (selections[y]->type != SEPARATOR)
  304.                 SetSelection(y);
  305.         }
  306.     }
  307.     else if (!rect.Inside(mx, my))    {
  308.         if (parent && my == parent->Bottom())
  309.             parent->LeftButton(mx, my);
  310.     }
  311.     prevmouseline = my;
  312.     prevmousecol = mx;
  313. }
  314.  
  315. void PopDown::DoubleClick(int mx, int my)
  316. {
  317.     if (!rect.Inside(mx, my))    {
  318.         CloseMenu(False);
  319.         if (parent)
  320.             parent->DoubleClick(mx, my);
  321.     }
  322. }
  323.  
  324. void PopDown::ButtonReleased(int mx, int my)
  325. {
  326.     if (ClientRect().Inside(mx, my))    {
  327.         if (prevmouseline == my && prevmousecol == mx)
  328.             if (selections[my-ClientTop()]->type != SEPARATOR)
  329.                 Choose();
  330.     }
  331.     else if (!rect.Inside(mx, my))    {
  332.         DFWindow *Wnd = inWindow(mx, my);
  333.         if (!(Wnd == parent && my == Top()-1 &&
  334.                 mx >= Left() && mx <= Right()))    {
  335.             CloseMenu(ParentisMenu());
  336.             if (Wnd != NULL && Wnd != desktop.InFocus())
  337.                 Wnd->SetFocus();
  338.         }
  339.     }
  340. }
  341.  
  342. void PopDown::Choose()
  343. {
  344.     MenuSelection &ms = *selections[selection];
  345.     if (ms.isEnabled())    {
  346.         if (ms.type == CASCADER && ms.cascade != NULL)
  347.             ms.cascade->OpenMenu(Right(), Top()+selection);
  348.         else    {
  349.             if (ms.type == TOGGLE)    {
  350.                 ms.InvertToggle();
  351.                 char *cp = TextLine(selection);
  352.                 if (*cp == CheckMark())
  353.                     *cp = ' ';
  354.                 else
  355.                     *cp = CheckMark();
  356.                 DisplayMenuLine(selection);
  357.             }
  358.             if (ms.cmdfunction != NULL)    {
  359.                 CloseMenu(iscascaded ? False : ParentisMenu());
  360.                 DFWindow *par = Parent();
  361.                 while (ParentisMenu(*par))    {
  362.                     par->Keyboard(ESC);
  363.                     par = par->Parent();
  364.                 }
  365.                 (par->*ms.cmdfunction)();
  366.             }
  367.         }
  368.     }
  369.     else
  370.         desktop.speaker().Beep();
  371. }
  372.  
  373. Bool PopDown::ParentisMenu(DFWindow &wnd)
  374. {
  375.     if (wnd.Parent() != NULL)    {
  376.         WndType wt = wnd.Parent()->WindowType();
  377.         return (Bool) (wt == MenubarWindow || wt == PopdownWindow);
  378.     }
  379.     return False;
  380. }
  381.  
  382.